#include "ProtoSockBase.h"
#include "base.h"
#include <cstdio>
#include <iostream>
#include <sys/socket.h>
#include <arpa/inet.h>

using namespace  std;

int ProtoSockBase::ReceiveProto(int fd, vector<Message *> & msglist)
{
	//先从输入缓冲区中读取描述符相关的所有数据
	string alldata;

	Socket::Recv(fd, alldata);

	if (alldata.empty())
	{
		//这下是真的对端关闭，导致读取到的数据为空
		return sock_close;
	}

	//分析收到的数据
	uint8_t * pdata = (uint8_t *)alldata.c_str();
	int length = alldata.length();
	unsigned offset = 0;

	cout<<"接收报文长度是:"<<length<<endl;
	int i = 0;
	while(offset < length)
	{
		//读取报文头数据
		cout<<i++<<"次解析报文"<<endl;
		int headsize = sizeof(PackHeader);

		PackHeader * pheader = (PackHeader *)(pdata + offset);

		//匹配是否指定报文
		if (0 != strcmp("YRC", pheader->sign))
		{
			return wrong_type_msg;
		}

		//大小端转换
		Socket::BigToSmallEndian((unsigned char *)&pheader->len, sizeof(pheader->len));
		unsigned packsize = pheader->len;

		offset += headsize; //偏移地址跨过报文头

		//分析报文
		//读取正文中的消息名字结构体
		ProtoNameHeader * pnamehead = (ProtoNameHeader *)(pdata + offset);
		Socket::BigToSmallEndian((unsigned char *)&pnamehead->namelen, sizeof(pnamehead->namelen));

		//消息名称
		char szMsgName[100] = { 0 };

	    int len = pnamehead->namelen > sizeof(szMsgName) ? sizeof(szMsgName) : pnamehead->namelen ;  //当长度数据异常时，会引发段错误

	    memcpy(szMsgName, pnamehead->name, len);

	    offset = offset + sizeof(ProtoNameHeader) + pnamehead->namelen - 1;

	    //消息头的长度，即消息名称头+消息名称长度
	    unsigned msgheadlen = sizeof(ProtoNameHeader) + pnamehead->namelen - 1;

		cout << "protoname:" << szMsgName << endl;

		const Descriptor * pdescrip = DescriptorPool::generated_pool()->FindMessageTypeByName(szMsgName);
		const Message * psg = MessageFactory::generated_factory()->GetPrototype(pdescrip);

		Message* preq = psg->New();

		//剩余的消息长度，应该是报文长度-中间的那些长度
		int msgsize = packsize - msgheadlen;

		uint8_t * msgdata = new uint8_t[msgsize];
		memset(msgdata, 0, msgsize);
		memcpy(msgdata, pdata + offset, msgsize);

		string strproto((char *)msgdata, msgsize);

		cout<<"消息数据内容的长度是:"<<strproto.size()<<endl;
		bool isok = preq->ParseFromString(strproto);

	    if (!isok)
	    {
	    	//获取错误类型
	    	delete[] msgdata;
	        return data_error_msg;
	    }

	    msglist.push_back(preq);
	    delete[] msgdata;
	    offset += msgsize;
	}

	return 0;
}

int ProtoSockBase::SendProto(int fd, Message * msg)
{
	//获得序列成字符串后的长度
	string strproto;

	msg->SerializeToString(&strproto);

	int size = strproto.size();

	//获取消息名称
	string type = msg->GetTypeName();

	size += type.size();
	size += sizeof(ProtoNameHeader) - 1;

	int packsize = size;

	size += sizeof(PackHeader);
	//proto消息内容的长度
	int len = size;

	int offset = 0;
	uint8_t * pcontent = new uint8_t[len];

	PackHeader * phead = (PackHeader *)pcontent;
	sprintf(phead->sign, "YRC");
	phead->len = packsize;

	Socket::SmallToBigEndian((unsigned char *)&phead->len, sizeof(phead->len));

	offset += sizeof(PackHeader);

	ProtoNameHeader * prothead = (ProtoNameHeader *)(pcontent + offset);

	prothead->namelen = type.size();
	Socket::SmallToBigEndian((unsigned char *)&prothead->namelen, sizeof(prothead->namelen));
	memcpy(prothead->name, type.c_str(), type.size());

	offset += sizeof(ProtoNameHeader) + type.size() - 1;
	memcpy(pcontent + offset, strproto.c_str(), strproto.size());

	Socket::Send(fd, (char *)pcontent, len);

	delete msg;

	cout<<"发送协议:"<<type<<"成功，报文长度是:"<<len<<endl;
	return 0;
}

int ProtoSockBase::PrintPeerName(int fd)
{
    //打印对端的IP+端口
    struct sockaddr_in peer;

    socklen_t peer_len = sizeof(peer);

    getpeername(fd, (struct sockaddr *)&peer, &peer_len);

    char peer_ip[20];
    inet_ntop(AF_INET, &peer.sin_addr, peer_ip, sizeof(peer_ip));

    cout<<"ip="<<peer_ip<<", port="<<ntohs(peer.sin_port)<<endl;

    return 0;
}
